/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.plupload.component;

import com.plupload.model.AttributesPackage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.plupload.model.TemporaryFile;
import com.plupload.servlet.PluploadServlet;
import java.awt.event.ActionListener;
import java.util.Map;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.faces.application.Resource;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ValueChangeEvent;
import javax.faces.event.ValueChangeListener;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;


/**
 *
 * @author Tiago Peres França
 */
public class SimpleQueueRenderer extends UIInput {
    private List<TemporaryFile> files;
    private long maxFileSize;
    private HttpSession session;
    
    /**
     * Builds the component
     * 
     * @param context The FacesContext
     * @throws IOException
     * @author Tiago Peres França
     * @version 0.2
     */
    @Override
    public void encodeBegin(FacesContext context) throws IOException{
        // get important attributes
        // list of uploaded temporary files.
        files = (ArrayList<TemporaryFile>) getAttributes().get("value");
        // maximum size per file (in bytes), 0 if there's no limit.
        String maxFileSizeStr = (String) getAttributes().get("maxFileSize");
        maxFileSize = (maxFileSizeStr != null) ? Long.parseLong(maxFileSizeStr) : 0;
        
        HttpServletRequest req = (HttpServletRequest) context.getExternalContext().getRequest();
        session = req.getSession(true);
        
        // render
        renderImports(context);
        renderScript(context);
        renderReplacebleCode(context);
    }
    
    /**
     * Render all the imports needed by the component. Called by "encodeBegin"
     * method. 
     * 
     * @param context The FacesContext
     * @throws IOException
     * @author Tiago Peres França
     * @version 0.2
     */
    private void renderImports(FacesContext context) throws IOException{
        // get language
        String lang = (String) getAttributes().get("language");
        
        // get resource files
        Resource css = FacesContext.getCurrentInstance().getApplication().getResourceHandler().createResource("jquery.plupload.queue.css", "plupload/js/jquery.plupload.queue/css");
        Resource jquery = FacesContext.getCurrentInstance().getApplication().getResourceHandler().createResource("jquery.min.js", "plupload");
        Resource browserplus = FacesContext.getCurrentInstance().getApplication().getResourceHandler().createResource("browserplus-min.js", "plupload");
        Resource pluploadFull = FacesContext.getCurrentInstance().getApplication().getResourceHandler().createResource("plupload.full.js", "plupload/js");
        Resource pluploadQueue = FacesContext.getCurrentInstance().getApplication().getResourceHandler().createResource("jquery.plupload.queue.js", "plupload/js/jquery.plupload.queue");
        Resource language = null;
        if (lang != null)
            language = FacesContext.getCurrentInstance().getApplication().getResourceHandler().createResource(lang + ".js", "plupload/js/i18n");
        
        // get writer
        ResponseWriter writer = context.getResponseWriter();
        
        // import css
        writer.startElement("link", this);
        writer.writeAttribute("rel", "stylesheet", null);
        writer.writeAttribute("type", "text/css", null);
        writer.writeAttribute("href", css.getRequestPath(), null);
        writer.endElement("link");
        
        //import jquery script
        writer.startElement("script", this);
        writer.writeAttribute("type", "text/javascript", null);
        writer.writeAttribute("src", jquery.getRequestPath(), null);
        writer.endElement("script");
        
        //import browserplus script
        writer.startElement("script", this);
        writer.writeAttribute("type", "text/javascript", null);
        writer.writeAttribute("src", browserplus.getRequestPath(), null);
        writer.endElement("script");
        
        //import "plupload full" script
        writer.startElement("script", this);
        writer.writeAttribute("type", "text/javascript", null);
        writer.writeAttribute("src", pluploadFull.getRequestPath(), null);
        writer.endElement("script");
        
        //import "plupload queue" script
        writer.startElement("script", this);
        writer.writeAttribute("type", "text/javascript", null);
        writer.writeAttribute("src", pluploadQueue.getRequestPath(), null);
        writer.endElement("script");
        
        //import language script
        if (language != null){
            writer.startElement("script", this);
            writer.writeAttribute("type", "text/javascript", null);
            writer.writeAttribute("src", language.getRequestPath(), null);
            writer.endElement("script");
        }
    }
    
    /**
     * Render the javascript that will be used by the component. Called by 
     * "encodeBegin".
     * 
     * @param context The FacesContext
     * @throws IOException
     * @author Tiago Peres França
     * @version 0.2
     */
    private void renderScript(FacesContext context) throws IOException{
        // get attributes
        // path for the plupload's servlet.
        String servletPath = (String) getAttributes().get("servletPath");
        // list of runtime preferences separated by comma.
        String runtimePreferences = (String) getAttributes().get("runtimePreferences");
        // width for image resizing. 0 if it's not relevent.
        String resizingWidthStr = (String) getAttributes().get("resizingWidth");
        int resizingWidth = (resizingWidthStr != null) ? Integer.parseInt(resizingWidthStr) : 0;
        // height for image resizing. 0 if it's not relevent.
        String resizingHeightStr = (String) getAttributes().get("resizingHeight");
        int resizingHeight = (resizingWidthStr != null) ? Integer.parseInt(resizingHeightStr) : 0;
        // quality for image resizing. 100 if it's not relevent.
        String resizingQualityStr = (String) getAttributes().get("resizingQuality");
        int resizingQuality = (resizingQualityStr != null) ? Integer.parseInt(resizingQualityStr) : 100;
        // list of allowed file extensions separated by comma.
        String allowedTypes = (String) getAttributes().get("allowedTypes");
        
        //treat default values for strings
        if (servletPath == null) servletPath = "plupload";
        if (runtimePreferences == null) runtimePreferences = "flash,silverlight,html5,gears,browserplus";
        if (allowedTypes == null) allowedTypes = "";
        
        // get writer
        ResponseWriter writer = context.getResponseWriter();
        
        // write script
        writer.startElement("script", this);
        writer.writeAttribute("type", "text/javascript", null);
        writer.write("$(function() {$(\"#uploaderB78EE5DCF63AA7412ECABB99\").pluploadQueue({runtimes : '");
        writer.write(runtimePreferences);
        writer.write("', url : '");
        writer.write(servletPath);
        /*writer.write("?JSESSIONID=");
        writer.write(session.getId());*/
        //writer.write("#");
        writer.write("', ");
        if (maxFileSize > 0){
            writer.write("max_file_size : '");
            writer.write(String.valueOf(maxFileSize));
            writer.write("', ");
        }
        writer.write("unique_names : false, ");
        if (resizingWidth > 0 || resizingHeight > 0 || resizingQuality < 100){
            writer.write("resize : {");
            if(resizingWidth > 0){
                writer.write("width : ");
                writer.write(String.valueOf(resizingWidth));
                writer.write(", ");
            }
            if (resizingHeight > 0){
                writer.write("height : ");
                writer.write(String.valueOf(resizingHeight));
                writer.write(", ");
            }
            writer.write("quality : ");
            writer.write(String.valueOf(resizingQuality));
            writer.write("}, ");
        }
        if (!allowedTypes.equals("")){
            writer.write("filters : [{title : \"Allowed files\", extensions : \"");
            writer.write(allowedTypes);
            writer.write("\"}], ");
        }
        Resource flash = FacesContext.getCurrentInstance().getApplication().getResourceHandler().createResource("plupload.flash.swf", "plupload/js");
        Resource silverlight = FacesContext.getCurrentInstance().getApplication().getResourceHandler().createResource("plupload.silverlight.xap", "plupload/js");
        writer.write("flash_swf_url : '");
        writer.write(flash.getRequestPath());
        writer.write("', silverlight_xap_url : '");
        writer.write(silverlight.getRequestPath());
        writer.write("'");
        writer.write("});});");
        writer.endElement("script");
    }
    
    /**
     * Render the div that will be replaced by the execution of the javascript
     * code rendered in "renderScript". Called by "encodeBegin".
     * 
     * @param context The FacesContext
     * @throws IOException
     * @author Tiago Peres França
     * @version 0.2
     */
    private void renderReplacebleCode(FacesContext context) throws IOException{
        // get attributes
        // Message for loading error
        String loadingErrorMsg = (String) getAttributes().get("loadingErrorMsg");
        if (loadingErrorMsg == null) 
            loadingErrorMsg = "Your browser doesn't have Flash, Silverlight, Gears, BrowserPlus or HTML5 support.";
        
        // get writer
        ResponseWriter writer = context.getResponseWriter();
        
        // render replaceble div
        writer.startElement("div", this);
        writer.writeAttribute("id", "uploaderB78EE5DCF63AA7412ECABB99", null);
        writer.startElement("p", this);
        writer.write(loadingErrorMsg);
        writer.endElement("p");
        writer.endElement("div");
    }
    
    @Override
    
    /**
     * It's the final part of rendering proccess. The variables to communicate
     * the FacesContext with the Plupload's servlet are declared here.
     * 
     * Strategy: declare an object of type "AttributesPackage" in session, this
     * object holds all information that is needed to threat any request comming
     * from the component.
     * 
     * Problem: for some reason Faces Context's session doesn't seem to be
     * accessible from Plupload's servlet. In Plupload's servlet 
     * "request.getSession(false)" aways returns null. Actually there's one
     * awkward exception to this problem: it works fine in Internet Explorer,
     * if the client is using IE, "request.getSession(false)" (in the servlet)
     * returns the correct session.
     * 
     * Alternative: For now, the "AttributesPackage" is being recorded in
     * session and in the application scope. The servlet tries to retrive it
     * from session, if sesssion is not accessible, it retrives the attributes
     * from the application scope. The problem with this aproach is obvious: if more
     * than one person executes the component at the same time it will go 
     * terribly wrong.
     * 
     * @param context The FacesContext
     * @author Tiago Peres França
     * @version 0.2
     */
    public void encodeEnd(FacesContext context){
        /*addValueChangeListener(
            new ValueChangeListener(){ 
                @Override
                public void processValueChange(ValueChangeEvent event) throws AbortProcessingException {
                    System.out.println("+++ caught: value changed!");
                }
            }
        );
        
        System.out.println(getValueChangeListeners().length + " listeners.");*/
        AttributesPackage atts = new AttributesPackage(files, maxFileSize);
        
        //context.getExternalContext().getFlash().put("plupload_attributes", atts);
        //System.out.println("+++++++++recording in session...");
        
        // record attributes in session (works just in IE O.o)
        session.setAttribute("plupload_attributes", atts);
        // record attributes in application
        context.getExternalContext().getApplicationMap().put("plupload_attributes", atts);
        
       /*Set keySet = facesAtts.keySet();
       Object keys[] = keySet.toArray();
       System.out.println("Atts in Faces Context");
       for (Object o : keys){
           System.out.println(o);
       }*/
        //context.getExternalContext().getSessionMap().put("plupload_attributes", atts);
        //System.out.println(session.getId());
        //context.getExternalContext().addResponseCookie("SESSIONID", FACETS_KEY, null)
        //System.out.println(session.getMaxInactiveInterval());
    }
    
    /**
     * Retrieves the component's family
     * 
     * @return the component's family.
     * @author Tiago Peres França
     * @version 0.2
     */
    @Override
    public String getFamily(){
        return "plupload";
    }
}
